﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MessageSystem.Managed.Infrastructure
{
    public unsafe class NetStream
    {
        private byte* m_pData;
        private UInt32 m_nLength;
        private UInt32 m_nReadPos;
        private UInt32 m_nWritePos;

        public void Reset(byte* pData, UInt32 nLength)
        {
            m_pData = pData;
            m_nLength = nLength;
            m_nReadPos = 0;
            m_nWritePos = 0;
        }

        internal void Reset()
        {
            m_nReadPos = 0;
            m_nWritePos = 0;
        }

        internal byte* DataPoint
        {
            get { return m_pData; }
        }

        public UInt32 ReadLength { get { return m_nReadPos; } }
        public UInt32 WriteLength { get { return m_nWritePos; } }
        public UInt32 DataLength { get { return m_nLength; } }

        public bool ReadBool()
        {
            return ReadByte() == 1;
        }

        public byte ReadByte()
        {
            TryRead(1);
            byte v = m_pData[m_nReadPos];
            m_nReadPos += 1;
            return v;
        }

        public sbyte ReadSByte()
        {
            TryRead(1);
            byte v = m_pData[m_nReadPos];
            m_nReadPos += 1;
            return (sbyte)v;
        }

        public UInt16 ReadUInt16()
        {
            TryRead(2);
            UInt16* pData = (UInt16*)(&m_pData[m_nReadPos]);
            m_nReadPos += 2;
            return *pData;
        }

        public Int16 ReadInt16()
        {
            TryRead(2);
            Int16* pData = (Int16*)(&m_pData[m_nReadPos]);
            m_nReadPos += 2;
            return *pData;
        }

        public UInt32 ReadUInt32()
        {
            TryRead(4);
            UInt32* pData = (UInt32*)(&m_pData[m_nReadPos]);
            m_nReadPos += 4;
            return *pData;
        }

        public Int32 ReadInt32()
        {
            TryRead(4);
            Int32* pData = (Int32*)(&m_pData[m_nReadPos]);
            m_nReadPos += 4;
            return *pData;
        }

        public UInt64 ReadUInt64()
        {
            TryRead(8);
            UInt64* pData = (UInt64*)(&m_pData[m_nReadPos]);
            m_nReadPos += 8;
            return *pData;
        }

        public Int64 ReadInt64()
        {
            TryRead(8);
            Int64* pData = (Int64*)(&m_pData[m_nReadPos]);
            m_nReadPos += 8;
            return *pData;
        }

        public float ReadFloat()
        {
            TryRead(4);
            float* pData = (float*)(&m_pData[m_nReadPos]);
            m_nReadPos += 4;
            return (float)*pData;
        }

        public String ReadString()
        {
            UInt16 length = ReadUInt16();
            if (0 == length)
            {
                return string.Empty;
            }
            else
            {
                TryRead(length);
                sbyte* pData = (sbyte*)(&m_pData[m_nReadPos]);
                m_nReadPos += length;

                return new String(pData, 0, length,Encoding.Unicode);
            }
        }

        public void WriteBool(bool v)
        {
            if (v)
            {
                WriteByte(1);
            }
            else
            {
                WriteByte(0);
            }
        }

        public void WriteByte(byte v)
        {
            TryWrite(1);
            m_pData[m_nWritePos] = v;
            m_nWritePos += 1;
        }

        public void WriteSByte(sbyte v)
        {
            TryWrite(1);
            m_pData[m_nWritePos] = (byte)v;
            m_nWritePos += 1;
        }

        public void WriteUInt16(UInt16 v)
        {
            TryWrite(2);
            UInt16* pData = (UInt16*)(&m_pData[m_nWritePos]);
            *pData = v;
            m_nWritePos += 2;
        }

        public void WriteInt16(Int16 v)
        {
            TryWrite(2);
            Int16* pData = (Int16*)(&m_pData[m_nWritePos]);
            *pData = v;
            m_nWritePos += 2;
        }

        public void WriteUInt32(UInt32 v)
        {
            TryWrite(4);
            UInt32* pData = (UInt32*)(&m_pData[m_nWritePos]);
            *pData = v;
            m_nWritePos += 4;
        }

        public void WriteInt32(Int32 v)
        {
            TryWrite(4);
            Int32* pData = (Int32*)(&m_pData[m_nWritePos]);
            *pData = v;
            m_nWritePos += 4;
        }

        public void WriteUInt64(UInt64 v)
        {
            TryWrite(8);
            UInt64* pData = (UInt64*)(&m_pData[m_nWritePos]);
            *pData = v;
            m_nWritePos += 8;
        }

        public void WriteInt64(Int64 v)
        {
            TryWrite(8);
            Int64* pData = (Int64*)(&m_pData[m_nWritePos]);
            *pData = v;
            m_nWritePos += 8;
        }

        public void WriteFloat(float f)
        {
            TryWrite(4);
            float* pData = (float*)(&m_pData[m_nWritePos]);
            *pData = f;
            m_nWritePos += 4;
        }

        public void WriteString(String s)
        {
            if (string.IsNullOrEmpty(s))
            {
                WriteUInt16(0);
            }
            else
            {
                byte[] bytes = Encoding.Unicode.GetBytes(s);
                UInt16 length = (UInt16)(bytes.Length);
                WriteUInt16(length);

                TryWrite(length);
                fixed (byte* pData = bytes)
                {
                    for (int i = 0; i < length; ++i)
                    {
                        m_pData[m_nWritePos + i] = pData[i];
                    }
                }
                m_nWritePos += length;
            }
        }

        private void TryRead(UInt32 nLength)
        {
            if (nLength + m_nReadPos > m_nLength)
                throw new Exception("TryRead Error");
        }

        private void TryWrite(UInt32 nLenght)
        {
            if (nLenght + m_nWritePos > m_nLength)
                throw new Exception("TryWrite Error");
        }

        public bool CanRead()
        {
            return m_nReadPos < m_nLength;
        }
    }
}
